// bslstl_stringrefdata.t.cpp                                         -*-C++-*-

#include <bslstl_stringrefdata.h>

#include <bslma_usesbslmaallocator.h>

#include <bslmf_isbitwisecopyable.h>
#include <bslmf_isbitwiseequalitycomparable.h>
#include <bslmf_istriviallydefaultconstructible.h>

#include <bsls_asserttest.h>
#include <bsls_bsltestutil.h>

#include <string>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>

using namespace BloombergLP;

//=============================================================================
//                                 TEST PLAN
//-----------------------------------------------------------------------------
//                                  Overview
//                                  --------
// The component under test implements a complex-constrained in-core
// value-semantic attribute class.  The Primary Manipulators and Basic
// Accessors are therefore, respectively, the attribute setters and getters,
// each of which follows our standard unconstrained attribute-type naming
// conventions: `setAttributeName` and `attributeName`.
//
// Primary Manipulators: none
//
// Basic Accessors:
//  - data
//  - length
//
// Certain standard value-semantic-type test cases are omitted:
//  - [10] -- BSLX streaming is not (yet) implemented for this class.
//
// Global Concerns:
//  - The test driver is robust w.r.t. reuse in other, similar components.
//  - ACCESSOR methods are declared `const`.
//  - CREATOR & MANIPULATOR pointer/reference parameters are declared `const`.
//  - Injected exceptions are safely propagated during memory allocation.
//  - Precondition violations are detected in appropriate build modes.
//
// Global Assumptions:
//  - ACCESSOR methods are `const` thread-safe.
//  - Individual attribute types are presumed to be *alias-safe*; hence, only
//    certain methods require the testing of this property:
//    - copy-assignment
//    - swap
//-----------------------------------------------------------------------------
// CLASS METHODS
// [12] size_t cStringLength(const CHAR_TYPE *data);
//
// CREATORS
// [ 2] bslstl::StringRefData();
// [ 3] bslstl::StringRefData(const char *begin, const char *end);
// [ 7] bslstl::StringRefData(const bslstl::StringRefData& other);
//
// MANIPULATORS
// [ 9] operator=(const bslstl::StringRefData& other);
//
// ACCESSORS
// [ 4] const CHAR_TYPE *data() const;
// [ 4] size_type length() const;
//
// FREE OPERATORS
// [ 5] bool operator==(const StringRefData& lhs, rhs);
// [ 5] bool operator!=(const StringRefData& lhs, rhs);
//
//-----------------------------------------------------------------------------
// [ 1] BREATHING TEST
// [13] USAGE EXAMPLE
// [10] Reserved for `bslx` streaming.
// [11] TYPE TRAITS

//=============================================================================
//                  STANDARD BDE ASSERT TEST MACROS
//-----------------------------------------------------------------------------
namespace {

int testStatus = 0;

void aSsErT(int c, const char *s, int i) {
    if (c) {
        printf("Error " __FILE__ "(%d): %s    (failed)\n", i, s);
        fflush(stdout);
        if (testStatus >= 0 && testStatus <= 100) ++testStatus;
    }
}

}  // close unnamed namespace

# define ASSERT(X) { aSsErT(!(X), #X, __LINE__); }

//=============================================================================
//                      STANDARD BDE TEST DRIVER MACROS
//-----------------------------------------------------------------------------
#define LOOP_ASSERT  BSLS_BSLTESTUTIL_LOOP_ASSERT
#define LOOP2_ASSERT BSLS_BSLTESTUTIL_LOOP2_ASSERT
#define LOOP3_ASSERT BSLS_BSLTESTUTIL_LOOP3_ASSERT
#define LOOP4_ASSERT BSLS_BSLTESTUTIL_LOOP4_ASSERT
#define LOOP5_ASSERT BSLS_BSLTESTUTIL_LOOP5_ASSERT
#define LOOP6_ASSERT BSLS_BSLTESTUTIL_LOOP6_ASSERT

#define Q   BSLS_BSLTESTUTIL_Q   // Quote identifier literally.
#define P   BSLS_BSLTESTUTIL_P   // Print identifier and value.
#define P_  BSLS_BSLTESTUTIL_P_  // `P(X)` without '\n'.
#define T_  BSLS_BSLTESTUTIL_T_  // Print a tab (w/o newline).
#define L_  BSLS_BSLTESTUTIL_L_  // current Line number

// ============================================================================
//                  NEGATIVE-TEST MACRO ABBREVIATIONS
// ----------------------------------------------------------------------------

#define ASSERT_SAFE_PASS(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_PASS(EXPR)
#define ASSERT_SAFE_FAIL(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_FAIL(EXPR)

//=============================================================================
//                      GLOBAL HELPER FUNCTIONS FOR TESTING
//-----------------------------------------------------------------------------

// Fundamental-type-specific print functions.
inline void dbg_print(bool b) { printf(b ? "true" : "false"); fflush(stdout); }
inline void dbg_print(char c) { printf("%c", c); fflush(stdout); }
inline void dbg_print(unsigned char c) { printf("%c", c); fflush(stdout); }
inline void dbg_print(signed char c) { printf("%c", c); fflush(stdout); }
inline void dbg_print(short val) { printf("%d", (int)val); fflush(stdout); }
inline void dbg_print(unsigned short val) {
    printf("%d", (int)val);
    fflush(stdout);
}
inline void dbg_print(int val) { printf("%d", val); fflush(stdout); }
inline void dbg_print(unsigned int val) { printf("%u", val); fflush(stdout); }
inline void dbg_print(long val) { printf("%ld", val); fflush(stdout); }
inline void dbg_print(unsigned long val) {
    printf("%lu", val);
    fflush(stdout);
}
inline void dbg_print(long long val) { printf("%lld", val); fflush(stdout); }
inline void dbg_print(unsigned long long val) {
    printf("%llu", val);
    fflush(stdout);
}
inline void dbg_print(float val) {
    printf("'%f'", (double)val);
    fflush(stdout);
}
inline void dbg_print(double val) { printf("'%f'", val); fflush(stdout); }
inline void dbg_print(long double val) {
    printf("'%Lf'", val);
    fflush(stdout);
}
inline void dbg_print(const char* s) { printf("\"%s\"", s); fflush(stdout); }
inline void dbg_print(char* s) { printf("\"%s\"", s); fflush(stdout); }
inline void dbg_print(void* p) { printf("%p", p); fflush(stdout); }

//=============================================================================
//                               USAGE EXAMPLE
//-----------------------------------------------------------------------------

///Usage
///-----
// This section illustrates intended usage of this component.
//
///Example 1: Breaking cyclic dependency between string and StringRef classes
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this example we demonstrate how `bslstl::StringRefData` allows us to
// break the cyclic dependency between hypothetical `String` and `StringRef`
// classes.
//
// Objects of our `String` and `StringRef` classes need to be
// convertible to each other.  However, only one of these classes can depend on
// the definition of the other one, otherwise they will be cyclically
// dependent.
//
// First, we define a hypothetical `String` class, whose implementation is
// intentionally simple and contains only the essential constructors and
// accessor methods; the important thing to notice is that `String` does not
// depend on `StringRef`, which has not been defined yet:
// ```
namespace Usage {

class String {
  private:
    const char *d_begin_p;
    const char *d_end_p;

  public:
    typedef const char *const_iterator;

    String(bslstl::StringRefData<char> const& stringRef)
    : d_begin_p(stringRef.data())
    , d_end_p(stringRef.data() + stringRef.length())
    {}

    const char *data() const
    {
        return d_begin_p;
    }

    std::size_t length() const
    {
        return static_cast<std::size_t>(d_end_p - d_begin_p);
    }
};
// ```
// Notice that the constructor of `String` takes a `bslstl::StringRefData`
// argument and then uses its members `data` and `length` to initialize the
// string object.
//
// Then, we define a hypothetical `StringRef` class, whose instances can be
// initialized either with a `String` object (to enable the conversion from
// `String` to `StringRef`) or with two `const char *` pointers:
// ```
class StringRef : public bslstl::StringRefData<char>
{
  public:
    StringRef(const char *begin, const char *end)
    : bslstl::StringRefData<char>(begin, end)
    {}

    StringRef(const String& str)
    : bslstl::StringRefData<char>(str.data(), str.data() + str.length())
    {}
};

}  // close namespace Usage
// ```

//=============================================================================
//                             PRIVATE FUNCTIONS
//-----------------------------------------------------------------------------

namespace {

// FREE OPERATORS

/// Return `true` if the specified `lhs` and `rhs` objects have the same
/// value, and `false` otherwise.  Two `bslstl::StringRefData` objects have
/// the same value if they have the same length, and the characters at each
/// respective position have the same value according to `CHAR_TRAITS::eq`.
template <class CHAR_TYPE>
bool operator==(const bslstl::StringRefData<CHAR_TYPE>& lhs,
                const bslstl::StringRefData<CHAR_TYPE>& rhs)
{
    typedef typename bslstl::StringRefData<CHAR_TYPE>::traits_type Traits;
    return lhs.size() == rhs.size()
        && 0 == Traits::compare(lhs.data(), rhs.data(), lhs.size());
}

/// Return `true` if the specified `lhs` and `rhs` objects do not have the
/// same value, and `false` otherwise.  Two `bslstl::StringRefData` objects
/// do not have the same value if they have different lengths or characters
/// at any respective position have different values.
template <class CHAR_TYPE>
bool operator!=(const bslstl::StringRefData<CHAR_TYPE>& lhs,
                const bslstl::StringRefData<CHAR_TYPE>& rhs)
{
    return !(lhs == rhs);
}

}  // close unnamed namespace

//=============================================================================
//                                MAIN PROGRAM
//-----------------------------------------------------------------------------

int main(int argc, char *argv[])
{
    int test = argc > 1 ? atoi(argv[1]) : 0;
    int verbose = argc > 2;
    int veryVerbose = argc > 3;

    printf("TEST " __FILE__ " CASE %d\n", test);

    // CONCERN: This test driver is reusable w/other, similar components.

    switch (test) { case 0:  // Zero is always the leading case.
      case 13: {
        // --------------------------------------------------------------------
        // USAGE EXAMPLE
        //
        // Concerns:
        // 1. The usage example provided in the component header file compiles,
        //    links, and runs as shown.
        //
        // Plan:
        // 1. Incorporate usage example from header into test driver, remove
        //    leading comment characters, and replace `assert` with `ASSERT`.
        //    (C-1)
        //
        // Testing:
        //   USAGE EXAMPLE
        // --------------------------------------------------------------------

        if (verbose) printf("\nTesting Usage Example"
                            "\n=====================\n");

// Note that `StringRef` also derives from `bslstl::StringRefData` so that an
// object of `StringRef` can be passed to the constructor of `String` as a
// reference to `bslstl::StringRefData`, which enables the conversion from
// `StringRef` to `String`.
//
// Finally, we verify that the conversions between `String` and `StringRef`
// work:
// ```
using Usage::String;
using Usage::StringRef;

const char str[] = "test string";
StringRef  strRef(str, str + sizeof(str));

String     strObj = strRef;     // convert `StringRef` to `String`
StringRef  strRf2 = strObj;     // convert `String` to `StringRef`

ASSERT(strObj.data()   == strRef.data());
ASSERT(strObj.length() == strRef.length());
ASSERT(strObj.data()   == strRf2.data());
ASSERT(strObj.length() == strRf2.length());
// ```
      } break;
      case 12: {
        // --------------------------------------------------------------------
        // TESTING `cStringLength`
        //
        // Concerns:
        // 1. `cStringLength` returns the same value as `strlen`.
        //
        // 2. QoI: Asserted precondition violations are detected when enabled.
        //
        // Plan:
        // 1. Check return value of `cStringLength` for known strings. (C-1)
        //
        // 2. Test the asserted preconditions using the `BSLS_ASSERTTEST_*`
        //    macros. (C-2)
        //
        // Testing:
        //   TYPE TRAITS
        //   size_t cStringLength(const CHAR_TYPE *data);
        // --------------------------------------------------------------------
          if (verbose) printf("\n"
                              "TESTING `cStringLength`\n"
                              "=======================\n");

          if (verbose) printf("\nchar\n");
          {
              typedef bslstl::StringRefData<char>    RefData;

              const char  data[]     = "123456789012345678901234567890";
              std::size_t numLetters =
                                            (sizeof(data) / sizeof(*data)) - 1;
              ASSERT(0 != data[numLetters - 1]);
              ASSERT(0 == data[numLetters    ]);

              std::size_t sizes[] = { 0, 1, 2, 7, 30 };
              enum { NUM_SIZES = sizeof(sizes) / sizeof(*sizes) };

              for (int i = 0; i < NUM_SIZES; ++i) {
                  if (veryVerbose) { T_ P_(i) P(sizes[i]) }

                  std::size_t  size = sizes[i];
                  const char *input = data + numLetters - size;
                  LOOP3_ASSERT(i, size,
                               RefData::cStringLength(input),
                               size == RefData::cStringLength(input));
              }


              if (verbose) printf("\tNegative Testing.\n");
              {
                  bsls::AssertTestHandlerGuard g;

                  ASSERT_SAFE_PASS(RefData::cStringLength(""));
                  ASSERT_SAFE_FAIL(RefData::cStringLength( 0));
              }
          }

          if (verbose) printf("\nwchar_t\n");
          {
              typedef bslstl::StringRefData<wchar_t> WRefData;

              const wchar_t data[]     = L"123456789012345678901234567890";
              std::size_t   numLetters = (sizeof(data) / sizeof(*data)) - 1;
              ASSERT(0 != data[numLetters - 1]);
              ASSERT(0 == data[numLetters    ]);

              std::size_t sizes[] = { 0, 1, 2, 7, 30 };
              enum { NUM_SIZES = sizeof(sizes) / sizeof(*sizes) };

              for (int i = 0; i < NUM_SIZES; ++i) {
                  if (veryVerbose) { T_ P_(i) P(sizes[i]) }

                  std::size_t size = sizes[i];
                  const wchar_t *input = data + numLetters - size;
                  LOOP3_ASSERT(i, size,
                               WRefData::cStringLength(input),
                               size == WRefData::cStringLength(input));
              }


              if (verbose) printf("\tNegative Testing.\n");
              {
                  bsls::AssertTestHandlerGuard g;

                  ASSERT_SAFE_PASS(WRefData::cStringLength(L""));
                  ASSERT_SAFE_FAIL(WRefData::cStringLength(  0));
              }
          }
      } break;
      case 11: {
        // --------------------------------------------------------------------
        // TESTING TYPE TRAITS
        //   The object is trivially copyable, and bitwise copyable and should
        //   have appropriate bsl type traits to reflect this.
        //
        // Concerns:
        // 1. The class has the `bsl::is_trivially_copyable` trait.
        //
        // 2. The class has the `bslmf::IsBitwiseMoveable` trait.
        //
        // 3. The class doesn't have the
        //    `bsl::is_trivially_default_constructible` trait.
        //
        // 4. The class doesn't have the `bslma::UsesBslmaAllocator` trait.
        //
        // 5. The class doesn't have the `bslmf::IsBitwiseEqualityComparable`
        //    trait.
        //
        // Plan:
        // 1. ASSERT the presence of each trait required by the type.  (C-1..5)
        //
        // Testing:
        //   TYPE TRAITS
        // --------------------------------------------------------------------
          if (verbose) printf("\n"
                              "TESTING TYPE TRAITS\n"
                              "===================\n");

          typedef bslstl::StringRefData<char>    RefData;
          typedef bslstl::StringRefData<wchar_t> WRefData;

          ASSERT(bslmf::IsBitwiseCopyable<RefData>::value);
          ASSERT(bslmf::IsBitwiseMoveable<RefData>::value);
          ASSERT(!bsl::is_trivially_default_constructible<RefData>::value);
          ASSERT(!bslma::UsesBslmaAllocator<RefData>::value);
          ASSERT(!bslmf::IsBitwiseEqualityComparable<RefData>::value);

          ASSERT(bslmf::IsBitwiseCopyable<WRefData>::value);
          ASSERT(bslmf::IsBitwiseMoveable<WRefData>::value);
          ASSERT(!bsl::is_trivially_default_constructible<WRefData>::value);
          ASSERT(!bslma::UsesBslmaAllocator<WRefData>::value);
          ASSERT(!bslmf::IsBitwiseEqualityComparable<WRefData>::value);

      } break;
      case 10: {
        // --------------------------------------------------------------------
        // BSLX STREAMING
        //   Ensure that we can serialize the value of any object of the class,
        //   and then deserialize that value back into any object of the class.
        //
        // Concerns:
        //   N/A
        //
        // Plan:
        //   N/A
        //
        // Testing:
        //   Reserved for `bslx` streaming.
        // --------------------------------------------------------------------

        if (verbose) printf("\nBSLX STREAMING"
                            "\n==============\n");

        if (verbose) printf("Not yet implemented.\n");

      } break;
      case 9: {
        // --------------------------------------------------------------------
        // COPY-ASSIGNMENT OPERATOR
        //   Ensure that we can assign the value of any object of the class to
        //   any object of the class, such that the two objects subsequently
        //   have the same value.
        //
        // Concerns:
        // 1. The assignment operator can change the value of any modifiable
        //    target object to that of any source object.
        //
        // 2. The allocator address held by the target object is unchanged.
        //
        // 3. Any memory allocation is from the target object's allocator.
        //
        // 4. The signature and return type are standard.
        //
        // 5. The reference returned is to the target object (i.e., `*this`).
        //
        // 6. The value of the source object is not modified.
        //
        // 7. The allocator address held by the source object is unchanged.
        //
        // 8. QoI: Assigning a source object having the default-constructed
        //    value allocates no memory.
        //
        // 9. Any memory allocation is exception neutral.
        //
        // 10. Assigning an object to itself behaves as expected (alias-safety).
        //
        // 11. Every object releases any allocated memory at destruction.
        //
        // Plan:
        // 1. Use the address of `operator=` to initialize a member-function
        //    pointer having the appropriate signature and return type for the
        //    copy-assignment operator defined in this component.  (C-4)
        //
        // 2. Create a `bslma::TestAllocator` object, and install it as the
        //    default allocator (note that a ubiquitous test allocator is
        //    already installed as the global allocator).
        //
        // 3. Using the table-driven technique:
        //
        //   1. Specify a set of (unique) valid object values (one per row) in
        //      terms of their individual attributes, including (a) first, the
        //      default value, (b) boundary values corresponding to every range
        //      of values that each individual attribute can independently
        //      attain, and (c) values that should require allocation from each
        //      individual attribute that can independently allocate memory.
        //
        //   2. Additionally, provide a (tri-valued) column, `MEM`, indicating
        //      the expectation of memory allocation for all typical
        //      implementations of individual attribute types: ('Y') "Yes",
        //      ('N') "No", or ('?') "implementation-dependent".
        //
        // 4. For each row `R1` (representing a distinct object value, `V`) in
        //    the table described in P-3:  (C-1..2, 5..8, 11)
        //
        //   1. Use the value constructor and a "scratch" allocator to create
        //      two `const` `Obj`, `Z` and `ZZ`, each having the value `V`.
        //
        //   2. Execute an inner loop that iterates over each row `R2`
        //      (representing a distinct object value, `W`) in the table
        //      described in P-3:
        //
        //   3. For each of the iterations (P-4.2):  (C-1..2, 5..8, 11)
        //
        //     1. Create a `bslma::TestAllocator` object, `oa`.
        //
        //     2. Use the value constructor and `oa` to create a modifiable
        //        `Obj`, `mX`, having the value `W`.
        //
        //     3. Assign `mX` from `Z` in the presence of injected exceptions
        //        (using the `BSLMA_TESTALLOCATOR_EXCEPTION_TEST_*` macros).
        //
        //     4. Verify that the address of the return value is the same as
        //        that of `mX`.  (C-5)
        //
        //     5. Use the equality-comparison operator to verify that: (C-1, 6)
        //
        //       1. The target object, `mX`, now has the same value as that of
        //          `Z`.  (C-1)
        //
        //       2. `Z` still has the same value as that of `ZZ`.  (C-6)
        //
        //     6. Use the `allocator` accessor of both `mX` and `Z` to verify
        //        that the respective allocator addresses held by the target
        //        and source objects are unchanged.  (C-2, 7)
        //
        //     7. Use the appropriate test allocators to verify that:
        //        (C-8, 11)
        //
        //       1. For an object that (a) is initialized with a value that did
        //          NOT require memory allocation, and (b) is then assigned a
        //          value that DID require memory allocation, the target object
        //          DOES allocate memory from its object allocator only
        //          (irrespective of the specific number of allocations or the
        //          total amount of memory allocated); also cross check with
        //          what is expected for `mX` and `Z`.
        //
        //       2. An object that is assigned a value that did NOT require
        //          memory allocation, does NOT allocate memory from its object
        //          allocator; also cross check with what is expected for `Z`.
        //
        //       3. No additional memory is allocated by the source object.
        //          (C-8)
        //
        //       4. All object memory is released when the object is destroyed.
        //          (C-11)
        //
        // 5. Repeat steps similar to those described in P-2 except that, this
        //    time, there is no inner loop (as in P-4.2); instead, the source
        //    object, `Z`, is a reference to the target object, `mX`, and both
        //    `mX` and `ZZ` are initialized to have the value `V`.  For each
        //    row (representing a distinct object value, `V`) in the table
        //    described in P-3:  (C-9)
        //
        //   1. Create a `bslma::TestAllocator` object, `oa`.
        //
        //   2. Use the value constructor and `oa` to create a modifiable `Obj`
        //      `mX`; also use the value constructor and a distinct "scratch"
        //      allocator to create a `const` `Obj` `ZZ`.
        //
        //   3. Let `Z` be a reference providing only `const` access to `mX`.
        //
        //   4. Assign `mX` from `Z` in the presence of injected exceptions
        //      (using the `BSLMA_TESTALLOCATOR_EXCEPTION_TEST_*` macros).
        //      (C-9)
        //
        //   5. Verify that the address of the return value is the same as that
        //      of `mX`.
        //
        //   6. Use the equality-comparison operator to verify that the
        //      target object, `mX`, still has the same value as that of `ZZ`.
        //
        //   7. Use the `allocator` accessor of `mX` to verify that it is still
        //      the object allocator.
        //
        //   8. Use the appropriate test allocators to verify that:
        //
        //     1. Any memory that is allocated is from the object allocator.
        //
        //     2. No additional (e.g., temporary) object memory is allocated
        //        when assigning an object value that did NOT initially require
        //        allocated memory.
        //
        //     3. All object memory is released when the object is destroyed.
        //
        // 6. Use the test allocator from P-2 to verify that no memory is ever
        //    allocated from the default allocator.  (C-3)
        //
        // Testing:
        //   operator=(const bslstl::StringRefData& rhs);
        // --------------------------------------------------------------------

        if (verbose) printf("\nCOPY-ASSIGNMENT OPERATOR"
                            "\n========================\n");

        static const struct {
            int         d_line;
            const char *d_str;
        } DATA[] = {
            //line string
            //---- ------

            { L_,  ""                           },
            { L_,  "a"                          },
            { L_,  "aa"                         },
            { L_,  "aaa"                        },
            { L_,  "aaaa"                       },
            { L_,  "aaaaa"                      },
            { L_,  "aaaaaa"                     },
        };

        const int NUM_DATA = sizeof DATA / sizeof *DATA;

        for (int i = 0; i != NUM_DATA; ++i) {
            const int          LINE   = DATA[i].d_line;
            const char        *STR    = DATA[i].d_str;
            const std::size_t  LENGTH = strlen(STR);

            bslstl::StringRefData<char> X(STR, STR + LENGTH);
            bslstl::StringRefData<char> Y;

            LOOP_ASSERT(LINE, STR    == X.data()  );
            LOOP_ASSERT(LINE, LENGTH == X.length());
            LOOP_ASSERT(LINE, 0      == Y.data()  );
            LOOP_ASSERT(LINE, 0      == Y.length());

            Y = X;

            LOOP_ASSERT(LINE, X.data()   == Y.data()  );
            LOOP_ASSERT(LINE, X.length() == Y.length());
        }

      } break;
      case 8: {
        // --------------------------------------------------------------------
        // SWAP MEMBER AND FREE FUNCTIONS
        //   Ensure that, when member and free `swap` are implemented, we can
        //   exchange the values of any two objects that use the same
        //   allocator.
        //
        // Concerns:
        //   N/A
        //
        // Plan:
        //   N/A
        //
        // Testing:
        //   Reserved for `swap` member and free functions.
        // --------------------------------------------------------------------

        if (verbose) printf("\nSWAP MEMBER AND FREE FUNCTIONS"
                            "\n==============================\n");

        if (verbose) printf("Not yet implemented.\n");

      } break;
      case 7: {
        // --------------------------------------------------------------------
        // COPY CONSTRUCTOR
        //   Ensure that we can create a distinct object of the class from any
        //   other one, such that the two objects have the same value.
        //
        // Concerns:
        // 1. The copy constructor (with or without a supplied allocator)
        //    creates an object having the same value as that of the supplied
        //    original object.
        //
        // 2. If an allocator is NOT supplied to the copy constructor, the
        //    default allocator in effect at the time of construction becomes
        //    the object allocator for the resulting object (i.e., the
        //    allocator of the original object is never copied).
        //
        // 3. If an allocator IS supplied to the copy constructor, that
        //    allocator becomes the object allocator for the resulting object.
        //
        // 4. Supplying a null allocator address has the same effect as not
        //    supplying an allocator.
        //
        // 5. Supplying an allocator to the copy constructor has no effect
        //    on subsequent object values.
        //
        // 6. Any memory allocation is from the object allocator.
        //
        // 7. There is no temporary memory allocation from any allocator.
        //
        // 8. Every object releases any allocated memory at destruction.
        //
        // 9. The original object is passed as a reference providing
        //    non-modifiable access to that object.
        //
        // 10. The value of the original object is unchanged.
        //
        // 11. The allocator address held by the original object is unchanged.
        //
        // 12. QoI: Copying an object having the default-constructed value
        //    allocates no memory.
        //
        // 13. Any memory allocation is exception neutral.
        //
        // Plan:
        // 1. Using the table-driven technique:
        //
        //   1. Specify a set of (unique) valid object values (one per row) in
        //      terms of their individual attributes, including (a) first, the
        //      default value, (b) boundary values corresponding to every range
        //      of values that each individual attribute can independently
        //      attain, and (c) values that should require allocation from each
        //      individual attribute that can independently allocate memory.
        //
        //   2. Additionally, provide a (tri-valued) column, `MEM`, indicating
        //      the expectation of memory allocation for all typical
        //      implementations of individual attribute types: ('Y') "Yes",
        //      ('N') "No", or ('?') "implementation-dependent".
        //
        // 2. For each row (representing a distinct object value, `V`) in the
        //    table described in P-1:  (C-1..12)
        //
        //   1. Use the value constructor and a "scratch" allocator to create
        //      two `const` `Obj`, `Z` and `ZZ`, each having the value `V`.
        //
        //   2. Execute an inner loop creating three distinct objects in turn,
        //      each using the copy constructor on `Z` from P-2.1, but
        //      configured differently: (a) without passing an allocator,
        //      (b) passing a null allocator address explicitly, and (c)
        //      passing the address of a test allocator distinct from the
        //      default.
        //
        //   3. For each of these three iterations (P-2.2):  (C-1..12)
        //
        //     1. Create three `bslma::TestAllocator` objects, and install one
        //        as the current default allocator (note that a ubiquitous test
        //        allocator is already installed as the global allocator).
        //
        //     2. Use the copy constructor to dynamically create an object `X`,
        //        with its object allocator configured appropriately (see
        //        P-2.2), supplying it the `const` object `Z` (see P-2.1); use
        //        a distinct test allocator for the object's footprint.  (C-9)
        //
        //     3. Use the equality-comparison operator to verify that:
        //        (C-1, 5, 10)
        //
        //       1. The newly constructed object, `X`, has the same value as
        //          that of `Z`.  (C-1, 5)
        //
        //       2. `Z` still has the same value as that of `ZZ`.  (C-10)
        //
        //     4. Use the `allocator` accessor of each underlying attribute
        //        capable of allocating memory to ensure that its object
        //        allocator is properly installed; also use the `allocator`
        //        accessor of `X` to verify that its object allocator is
        //        properly installed, and use the `allocator` accessor of `Z`
        //        to verify that the allocator address that it holds is
        //        unchanged.  (C-6, 11)
        //
        //     5. Use the appropriate test allocators to verify that:  (C-2..4,
        //        7..8, 12)
        //
        //       1. An object that IS expected to allocate memory does so
        //          from the object allocator only (irrespective of the
        //          specific number of allocations or the total amount of
        //          memory allocated).  (C-2, 4)
        //
        //       2. An object that is expected NOT to allocate memory doesn't.
        //          (C-12)
        //
        //       3. If an allocator was supplied at construction (P-2.1c), the
        //          current default allocator doesn't allocate any memory.
        //          (C-3)
        //
        //       4. No temporary memory is allocated from the object allocator.
        //          (C-7)
        //
        //       5. All object memory is released when the object is destroyed.
        //          (C-8)
        //
        // 3. Test again, using the data of P-1, but this time just for the
        //    supplied allocator configuration (P-2.2c), and create the object
        //    as an automatic variable in the presence of injected exceptions
        //    (using the `BSLMA_TESTALLOCATOR_EXCEPTION_TEST_*` macros).
        //    (C-13)
        //
        // Testing:
        //   bslstl::StringRefData(const bslstl::StringRefData& other);
        // --------------------------------------------------------------------

        if (verbose) printf("\nCOPY CONSTRUCTOR"
                            "\n================\n");

        static const struct {
            int         d_line;
            const char *d_str;
        } DATA[] = {
            //line string
            //---- ------

            { L_,  ""                           },
            { L_,  "a"                          },
            { L_,  "aa"                         },
            { L_,  "aaa"                        },
            { L_,  "aaaa"                       },
            { L_,  "aaaaa"                      },
            { L_,  "aaaaaa"                     },
        };

        const int NUM_DATA = sizeof DATA / sizeof *DATA;

        for (int i = 0; i != NUM_DATA; ++i) {
            const int          LINE   = DATA[i].d_line;
            const char        *STR    = DATA[i].d_str;
            const std::size_t  LENGTH = strlen(STR);

            bslstl::StringRefData<char> X(STR, STR + LENGTH);

            LOOP_ASSERT(LINE, STR    == X.data()  );
            LOOP_ASSERT(LINE, LENGTH == X.length());

            bslstl::StringRefData<char> Y(X);

            LOOP_ASSERT(LINE, STR    == Y.data()  );
            LOOP_ASSERT(LINE, LENGTH == Y.length());
        }
      } break;
      case 6: {
        // --------------------------------------------------------------------
        // EQUALITY-COMPARISON OPERATORS
        //   Ensure that `==` and `!=` are the operational definition of value.
        //
        // Concerns:
        // 1. Two objects, `X` and `Y`, compare equal if and only if each of
        //    their corresponding salient attributes respectively compares
        //    equal.
        //
        // 2. All salient attributes participate in the comparison.
        //
        // 3. No non-salient attributes (i.e., `allocator`) participate.
        //
        // 4. `true  == (X == X)`  (i.e., identity)
        //
        // 5. `false == (X != X)`  (i.e., identity)
        //
        // 6. `X == Y` if and only if `Y == X`  (i.e., commutativity)
        //
        // 7. `X != Y` if and only if `Y != X`  (i.e., commutativity)
        //
        // 8. `X != Y` if and only if `!(X == Y)`
        //
        // 9. Comparison is symmetric with respect to user-defined conversion
        //    (i.e., both comparison operators are free functions).
        //
        // 10. Non-modifiable objects can be compared (i.e., objects or
        //    references providing only non-modifiable access).
        //
        // 11. No memory allocation occurs as a result of comparison (e.g., the
        //    arguments are not passed by value).
        //
        // 12. The equality operator's signature and return type are standard.
        //
        // 13. The inequality operator's signature and return type are standard.
        //
        // Plan:
        // 1. Use the respective addresses of `operator==` and `operator!=` to
        //    initialize function pointers having the appropriate signatures
        //    and return types for the two homogeneous, free equality-
        //    comparison operators defined in this component.
        //    (C-9..10, 12..13)
        //
        // 2. Create a `bslma::TestAllocator` object, and install it as the
        //    default allocator (note that a ubiquitous test allocator is
        //    already installed as the global allocator).
        //
        // 3. Using the table-driven technique, specify a set of distinct
        //    object values (one per row) in terms of their individual salient
        //    attributes such that (a) for each salient attribute, there exists
        //    a pair of rows that differ (slightly) in only the column
        //    corresponding to that attribute, and (b) all attribute values
        //    that can allocate memory on construction do so.
        //
        // 4. For each row `R1` in the table of P-3:  (C-1..8)
        //
        //   1. Create a single object, using a "scratch" allocator, and
        //      use it to verify the reflexive (anti-reflexive) property of
        //      equality (inequality) in the presence of aliasing.  (C-4..5)
        //
        //   2. For each row `R2` in the table of P-3:  (C-1..3, 6..8)
        //
        //     1. Record, in `EXP`, whether or not distinct objects created
        //        from `R1` and `R2`, respectively, are expected to have the
        //        same value.
        //
        //     2. For each of two configurations, `a` and `b`:  (C-1..3, 6..8)
        //
        //       1. Create two (object) allocators, `oax` and `oay`.
        //
        //       2. Create an object `X`, using `oax`, having the value `R1`.
        //
        //       3. Create an object `Y`, using `oax` in configuration `a` and
        //          `oay` in configuration `b`, having the value `R2`.
        //
        //       4. Verify the commutativity property and expected return value
        //          for both `==` and `!=`, while monitoring both `oax` and
        //          `oay` to ensure that no object memory is ever allocated by
        //          either operator.  (C-1..3, 6..8)
        //
        // 5. Use the test allocator from P-2 to verify that no memory is ever
        //    allocated from the default allocator.  (C-11)
        //
        // Testing:
        //   bool operator==(const bslstl::StringRefData& lhs, rhs);
        //   bool operator!=(const bslstl::StringRefData& lhs, rhs);
        // --------------------------------------------------------------------

        if (verbose) printf("\nEQUALITY-COMPARISON OPERATORS"
                            "\n=============================\n");

        static const struct {
            int         d_line;
            const char *d_str;
        } DATA[] = {
            //line string
            //---- ------

            { L_,  ""                           },
            { L_,  "a"                          },
            { L_,  "aa"                         },
            { L_,  "aaa"                        },
            { L_,  "aaaa"                       },
            { L_,  "aaaaa"                      },
            { L_,  "aaaaaa"                     },
        };

        const int NUM_DATA = sizeof DATA / sizeof *DATA;

        for (int i = 0; i != NUM_DATA; ++i) {
            const int   LINE = DATA[i].d_line;
            const char *STR  = DATA[i].d_str;

            bslstl::StringRefData<char> X(STR, STR + strlen(STR));
            bslstl::StringRefData<char> Y(STR, STR + strlen(STR));

            // test `operator==`
            LOOP_ASSERT(LINE, X == Y);

            if (i > 0) {
                // modify values slightly
                bslstl::StringRefData<char> Y1(STR, STR + strlen(STR) - 1);
                LOOP_ASSERT(LINE, X != Y1);

                bslstl::StringRefData<char> Y2(STR + 1, STR + strlen(STR));
                LOOP_ASSERT(LINE, X != Y2);

                // compare with a previous value
                const char *STRPREV = DATA[i - 1].d_str;
                bslstl::StringRefData<char> Z(STRPREV,
                                              STRPREV + strlen(STRPREV));

                LOOP_ASSERT(LINE, X != Z);
            }
        }

      } break;
      case 5: {
        // --------------------------------------------------------------------
        // PRINT AND OUTPUT OPERATOR
        //   Ensure that the value of the object can be formatted appropriately
        //   on an `ostream` in some standard, human-readable form.
        //
        //
        // Concerns:
        //   N/A
        //
        // Plan:
        //   N/A
        //
        // Testing:
        //   Reserved for print and output operators.
        // --------------------------------------------------------------------

        if (verbose) printf("\nPRINT AND OUTPUT OPERATOR"
                            "\n=========================\n");

        if (verbose) printf("Not yet implemented.\n");

      } break;
      case 4: {
        // --------------------------------------------------------------------
        // BASIC ACCESSORS
        //   Ensure each basic accessor properly interprets object state.
        //
        // Concerns:
        // 1. Each accessor returns the value of the corresponding attribute
        //    of the object.
        //
        // 2. Each accessor method is declared `const`.
        //
        // 3. No accessor allocates any memory.
        //
        // 4. Accessors for attributes that can allocate memory (i.e., those
        //    that take an allocator in their constructor) return a reference
        //    providing only non-modifiable access.
        //
        // Plan:
        //   In case 3 we demonstrated that all basic accessors work properly
        //   with respect to attributes initialized by the value constructor.
        //   Here we use the default constructor and primary manipulators,
        //   which were fully tested in case 2, to further corroborate that
        //   these accessors are properly interpreting object state.
        //
        // 1. Create two `bslma::TestAllocator` objects, and install one as
        //    the current default allocator (note that a ubiquitous test
        //    allocator is already installed as the global allocator).
        //
        // 2. Use the default constructor, using the other test allocator
        //    from P-1, to create an object (having default attribute values).
        //
        // 3. Verify that each basic accessor, invoked on a reference providing
        //    non-modifiable access to the object created in P2, returns the
        //    expected value.  (C-2)
        //
        // 4. For each salient attribute (contributing to value):  (C-1, 3..4)
        //   1. Use the corresponding primary manipulator to set the attribute
        //      to a unique value, making sure to allocate memory if possible.
        //
        //   2. Use the corresponding basic accessor to verify the new
        //      expected value.  (C-1)
        //
        //   3. Monitor the memory allocated from both the default and object
        //      allocators before and after calling the accessor; verify that
        //      there is no change in total memory allocation.  (C-3..4)
        //
        // Testing:
        //   const CHAR_TYPE *data() const;
        //   size_type length() const;
        // --------------------------------------------------------------------

        if (verbose) printf("\nBASIC ACCESSORS"
                            "\n===============\n");

        static const struct {
            int         d_line;
            const char *d_str;
        } DATA[] = {
            //line string
            //---- ------

            { L_,  ""                           },
            { L_,  "a"                          },
            { L_,  "aa"                         },
            { L_,  "aaa"                        },
            { L_,  "aaaa"                       },
            { L_,  "aaaaa"                      },
            { L_,  "aaaaaa"                     },
        };

        const int NUM_DATA = sizeof DATA / sizeof *DATA;

        for (int i = 0; i != NUM_DATA; ++i) {
            const int          LINE   = DATA[i].d_line;
            const char        *STR    = DATA[i].d_str;
            const std::size_t  LENGTH = strlen(STR);

            bslstl::StringRefData<char> Y(STR, STR + LENGTH);

            LOOP_ASSERT(LINE, STR    == Y.data());
            LOOP_ASSERT(LINE, LENGTH == Y.length());
        }

      } break;
      case 3: {
        // --------------------------------------------------------------------
        // VALUE CTOR
        //   Ensure that we can put an object into any initial state relevant
        //   for thorough testing.
        //
        // Concerns:
        // 1. The value constructor (with or without a supplied allocator) can
        //    create an object having any value that does not violate the
        //    constructor's documented preconditions.
        //
        // 2. Any string arguments can be of type `char *` or `string`.
        //
        // 3. Any argument can be `const`.
        //
        // 4. If an allocator is NOT supplied to the value constructor, the
        //    default allocator in effect at the time of construction becomes
        //    the object allocator for the resulting object.
        //
        // 5. If an allocator IS supplied to the value constructor, that
        //    allocator becomes the object allocator for the resulting object.
        //
        // 6. Supplying a null allocator address has the same effect as not
        //    supplying an allocator.
        //
        // 7. Supplying an allocator to the value constructor has no effect
        //    on subsequent object values.
        //
        // 8. Any memory allocation is from the object allocator.
        //
        // 9. There is no temporary memory allocation from any allocator.
        //
        // 10. Every object releases any allocated memory at destruction.
        //
        // 11. QoI: Creating an object having the default-constructed value
        //    allocates no memory.
        //
        // 12. Any memory allocation is exception neutral.
        //
        // 13. QoI: Asserted precondition violations are detected when enabled.
        //
        // Plan:
        // 1. Using the table-driven technique:
        //
        //   1. Specify a set of (unique) valid object values (one per row) in
        //      terms of their individual attributes, including (a) first, the
        //      default value, (b) boundary values corresponding to every range
        //      of values that each individual attribute can independently
        //      attain, and (c) values that should require allocation from each
        //      individual attribute that can independently allocate memory.
        //
        //   2. Additionally, provide a (tri-valued) column, `MEM`, indicating
        //      the expectation of memory allocation for all typical
        //      implementations of individual attribute types: ('Y') "Yes",
        //      ('N') "No", or ('?') "implementation-dependent".
        //
        // 2. For each row (representing a distinct object value, `V`) in the
        //    table described in P-1:  (C-1, 3..11)
        //
        //   1. Execute an inner loop creating three distinct objects, in turn,
        //      each object having the same value, `V`, but configured
        //      differently: (a) without passing an allocator, (b) passing a
        //      null allocator address explicitly, and (c) passing the address
        //      of a test allocator distinct from the default allocator.
        //
        //   2. For each of the three iterations in P-2.1:  (C-1, 4..11)
        //
        //     1. Create three `bslma::TestAllocator` objects, and install one
        //        as the current default allocator (note that a ubiquitous test
        //        allocator is already installed as the global allocator).
        //
        //     2. Use the value constructor to dynamically create an object
        //        having the value `V`, with its object allocator configured
        //        appropriately (see P-2.1), supplying all the arguments as
        //        `const` and representing any string arguments as `char *`;
        //        use a distinct test allocator for the object's footprint.
        //
        //     3. Use the (as yet unproven) salient attribute accessors to
        //        verify that all of the attributes of each object have their
        //        expected values.  (C-1, 7)
        //
        //     4. Use the `allocator` accessor of each underlying attribute
        //        capable of allocating memory to ensure that its object
        //        allocator is properly installed; also invoke the (as yet
        //        unproven) `allocator` accessor of the object under test.
        //        (C-8)
        //
        //     5. Use the appropriate test allocators to verify that:  (C-4..6,
        //        9..11)
        //
        //       1. An object that IS expected to allocate memory does so
        //          from the object allocator only (irrespective of the
        //          specific number of allocations or the total amount of
        //          memory allocated).  (C-4, 6)
        //
        //       2. An object that is expected NOT to allocate memory doesn't.
        //          (C-11)
        //
        //       3. If an allocator was supplied at construction (P-2.1c), the
        //          default allocator doesn't allocate any memory.  (C-5)
        //
        //       4. No temporary memory is allocated from the object allocator.
        //          (C-9)
        //
        //       5. All object memory is released when the object is destroyed.
        //          (C-10)
        //
        // 3. Repeat the steps in P-2 for the supplied allocator configuration
        //    (P-2.1c) on the data of P-1, but this time create the object as
        //    an automatic variable in the presence of injected exceptions
        //    (using the `BSLMA_TESTALLOCATOR_EXCEPTION_TEST_*` macros);
        //    represent any string arguments in terms of `string` using a
        //    "scratch" allocator.  (C-2, 12)
        //
        // 4. Verify that, in appropriate build modes, defensive checks are
        //    triggered for invalid attribute values, but not triggered for
        //    adjacent valid ones (using the `BSLS_ASSERTTEST_*` macros).
        //    (C-13)
        //
        // Testing:
        //   bslstl::StringRefData(const char *begin, const char *end);
        // --------------------------------------------------------------------

        if (verbose) printf("\nVALUE CTOR"
                            "\n==========\n");

        if (veryVerbose) printf("\tTesting the constructor with parameters\n");

        static const struct {
            int         d_line;
            const char *d_str;
        } DATA[] = {
            //line string
            //---- ------

            { L_,  ""                           },
            { L_,  "a"                          },
            { L_,  "aa"                         },
            { L_,  "aaa"                        },
            { L_,  "aaaa"                       },
            { L_,  "aaaaa"                      },
            { L_,  "aaaaaa"                     },
        };

        const int NUM_DATA = sizeof DATA / sizeof *DATA;

        for (int i = 0; i != NUM_DATA; ++i) {
            const int          LINE   = DATA[i].d_line;
            const char        *STR    = DATA[i].d_str;
            const std::size_t  LENGTH = strlen(STR);

            bslstl::StringRefData<char> Y(STR, STR + LENGTH);

            LOOP_ASSERT(LINE, STR    == Y.data());
            LOOP_ASSERT(LINE, LENGTH == Y.length());
        }

      } break;
      case 2: {
        // --------------------------------------------------------------------
        // DEFAULT CTOR, PRIMARY MANIPULATORS, & DTOR
        //   Ensure that we can use the default constructor to create an
        //   object (having the default-constructed value), use the primary
        //   manipulators to put that object into any state relevant for
        //   thorough testing, and use the destructor to destroy it safely.
        //
        // Concerns:
        // 1. An object created with the default constructor (with or without
        //    a supplied allocator) has the contractually specified default
        //    value.
        //
        // 2. If an allocator is NOT supplied to the default constructor, the
        //    default allocator in effect at the time of construction becomes
        //    the object allocator for the resulting object.
        //
        // 3. If an allocator IS supplied to the default constructor, that
        //    allocator becomes the object allocator for the resulting object.
        //
        // 4. Supplying a null allocator address has the same effect as not
        //    supplying an allocator.
        //
        // 5. Supplying an allocator to the default constructor has no effect
        //    on subsequent object values.
        //
        // 6. Any memory allocation is from the object allocator.
        //
        // 7. There is no temporary allocation from any allocator.
        //
        // 8. Every object releases any allocated memory at destruction.
        //
        // 9. QoI: The default constructor allocates no memory.
        //
        // 10. Each attribute is modifiable independently.
        //
        // 11. Each attribute can be set to represent any value that does not
        //    violate that attribute's documented constraints.
        //
        // 12. Any string arguments can be of type `char *` or `string`.
        //
        // 13. Any argument can be `const`.
        //
        // 14. Any memory allocation is exception neutral.
        //
        // 15. QoI: Asserted precondition violations are detected when enabled.
        //
        // Plan:
        // 1. Create three sets of attribute values for the object: (`D`)
        //    values corresponding to the default-constructed object, (`A`)
        //    values that allocate memory if possible, and (`B`) other values
        //    that do not cause additional memory allocation beyond that which
        //    may be incurred by `A`.  Both the `A` and `B` attribute values
        //    should be chosen to be boundary values where possible.  If an
        //    attribute can be supplied via alternate C++ types (e.g., `string`
        //    instead of `char *`), use the alternate type for `B`.
        //
        // 2. Using a loop-based approach, default-construct three distinct
        //    objects, in turn, but configured differently: (a) without passing
        //    an allocator, (b) passing a null allocator address explicitly,
        //    and (c) passing the address of a test allocator distinct from the
        //    default.  For each of these three iterations:  (C-1..14)
        //
        //   1. Create three `bslma::TestAllocator` objects, and install one as
        //      as the current default allocator (note that a ubiquitous test
        //      allocator is already installed as the global allocator).
        //
        //   2. Use the default constructor to dynamically create an object
        //      `X`, with its object allocator configured appropriately (see
        //      P-2); use a distinct test allocator for the object's footprint.
        //
        //   3. Use the `allocator` accessor of each underlying attribute
        //      capable of allocating memory to ensure that its object
        //      allocator is properly installed; also invoke the (as yet
        //      unproven) `allocator` accessor of the object under test.
        //      (C-2..4)
        //
        //   4. Use the appropriate test allocators to verify that no memory
        //      is allocated by the default constructor.  (C-9)
        //
        //   5. Use the individual (as yet unproven) salient attribute
        //      accessors to verify the default-constructed value.  (C-1)
        //
        //   6. For each attribute `i`, in turn, create a local block.  Then
        //      inside the block, using brute force, set that attribute's
        //      value, passing a `const` argument representing each of the
        //      three test values, in turn (see P-1), first to `Ai`, then to
        //      `Bi`, and finally back to `Di`.  If attribute `i` can allocate
        //      memory, verify that it does so on the first value transition
        //      (`Di` -> `Ai`), and that the corresponding primary manipulator
        //      is exception neutral (using the
        //      `BSLMA_TESTALLOCATOR_EXCEPTION_TEST_*` macros).  In all other
        //      cases, verify that no memory allocation occurs.  After each
        //      transition, use the (as yet unproven) basic accessors to verify
        //      that only the intended attribute value changed.  (C-5..6,
        //      11..14)
        //
        //   7. Corroborate that attributes are modifiable independently by
        //      first setting all of the attributes to their `A` values, then
        //      setting all of the attributes to their `B` values.  (C-10)
        //
        //   8. Verify that no temporary memory is allocated from the object
        //      allocator.  (C-7)
        //
        //   9. Verify that all object memory is released when the object is
        //      destroyed.  (C-8)
        //
        // 3. Verify that, in appropriate build modes, defensive checks are
        //    triggered for invalid attribute values, but not triggered for
        //    adjacent valid ones (using the `BSLS_ASSERTTEST_*` macros).
        //    (C-15)
        //
        // Testing:
        //   bslstl::StringRefData();
        // --------------------------------------------------------------------

        if (verbose) printf("\nDEFAULT CTOR, PRIMARY MANIPULATORS, & DTOR"
                            "\n==========================================\n");

        if (veryVerbose) printf("\tTesting the default constructor\n");

        bslstl::StringRefData<char> X;

        ASSERT(0 == X.data());
        ASSERT(0 == X.length());

      } break;
      case 1: {
        // --------------------------------------------------------------------
        // BREATHING TEST
        //   This case exercises (but does not fully test) basic functionality.
        //
        // Concerns:
        // 1. The class is sufficiently functional to enable comprehensive
        //    testing in subsequent test cases.
        //
        // Plan:
        // 1. Create an object `w` (default ctor).       { w:D             }
        // 2. Create an object `x` (copy from `w`).      { w:D x:D         }
        // 3. Set `x` to `A` (value distinct from `D`).  { w:D x:A         }
        // 4. Create an object `y` (init. to `A`).       { w:D x:A y:A     }
        // 5. Create an object `z` (copy from `y`).      { w:D x:A y:A z:A }
        // 6. Set `z` to `D` (the default value).        { w:D x:A y:A z:D }
        // 7. Assign `w` from `x`.                       { w:A x:A y:A z:D }
        // 8. Assign `w` from `z`.                       { w:D x:A y:A z:D }
        // 9. Assign `x` from `x` (aliasing).            { w:D x:A y:A z:D }
        //
        // Testing:
        //   BREATHING TEST
        // --------------------------------------------------------------------

        if (verbose) printf("\nBREATHING TEST"
                            "\n==============\n");

        typedef bslstl::StringRefData<char> Obj;

        // Attribute Types

        typedef const char *T1;
        typedef const char *T2;

        // Attribute Values

        const char str[] = "abced";

        const T1 D1 = 0;                // default value
        const T1 A1 = str;

        const T2 D2 = 0;                // default value
        const T2 A2 = str + sizeof str;

        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        if (verbose) printf("\n 1. Create an object `w` (default ctor)."
                            "\t\t{ w:D             }\n");

        Obj mW;  const Obj& W = mW;

        if (veryVerbose) printf("\ta. Check initial value of `w`.\n");

        ASSERT(D1 == W.data()             );
        ASSERT(D2 == W.data() + W.length());

        if (veryVerbose) printf(
                               "\tb. Try equality operators: `w` <op> `w`.\n");

        ASSERT(1 == (W == W));        ASSERT(0 == (W != W));

        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        if (verbose) printf("\n 2. Create an object `x` (copy from `w`)."
                            "\t\t{ w:D x:D         }\n");

        Obj mX(W);  const Obj& X = mX;

        if (veryVerbose) printf("\ta. Check initial value of `x`.\n");

        ASSERT(D1 == X.data()             );
        ASSERT(D2 == X.data() + X.length());

        if (veryVerbose) printf(
                          "\tb. Try equality operators: `x` <op> `w`, `x`.\n");

        ASSERT(1 == (X == W));        ASSERT(0 == (X != W));
        ASSERT(1 == (X == X));        ASSERT(0 == (X != X));

        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        if (verbose) printf("\n 3. Set `x` to `A` (value distinct from `D`)."
                            "\t\t{ w:D x:A         }\n");

        mX = Obj(A1, A2);

        if (veryVerbose) printf("\ta. Check new value of `x`.\n");

        ASSERT(A1 == X.data()             );
        ASSERT(A2 == X.data() + X.length());

        if (veryVerbose) printf(
                          "\tb. Try equality operators: `x` <op> `w`, `x`.\n");

        ASSERT(0 == (X == W));        ASSERT(1 == (X != W));
        ASSERT(1 == (X == X));        ASSERT(0 == (X != X));

        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        if (verbose) printf("\n 4. Create an object `y` (init. to `A`)."
                            "\t\t{ w:D x:A y:A     }\n");

        Obj mY(A1, A2);  const Obj& Y = mY;

        if (veryVerbose) printf("\ta. Check initial value of `y`.\n");

        ASSERT(A1 == Y.data()             );
        ASSERT(A2 == Y.data() + Y.length());

        if (veryVerbose) printf(
                      "\tb. Try equality operators: `y` <op> `w`, `x`, `y`\n");

        ASSERT(0 == (Y == W));        ASSERT(1 == (Y != W));
        ASSERT(1 == (Y == X));        ASSERT(0 == (Y != X));
        ASSERT(1 == (Y == Y));        ASSERT(0 == (Y != Y));

        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        if (verbose) printf("\n 5. Create an object `z` (copy from `y`)."
                            "\t\t{ w:D x:A y:A z:A }\n");

        Obj mZ(Y);  const Obj& Z = mZ;

        if (veryVerbose) printf("\ta. Check initial value of `z`.\n");

        ASSERT(A1 == Z.data()             );
        ASSERT(A2 == Z.data() + Z.length());

        if (veryVerbose) printf(
                "\tb. Try equality operators: `z` <op> `w`, `x`, `y`, `z`.\n");

        ASSERT(0 == (Z == W));        ASSERT(1 == (Z != W));
        ASSERT(1 == (Z == X));        ASSERT(0 == (Z != X));
        ASSERT(1 == (Z == Y));        ASSERT(0 == (Z != Y));
        ASSERT(1 == (Z == Z));        ASSERT(0 == (Z != Z));

        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        if (verbose) printf("\n 6. Set `z` to `D` (the default value)."
                            "\t\t\t{ w:D x:A y:A z:D }\n");

        mZ = Obj(D1, D2);

        if (veryVerbose) printf("\ta. Check new value of `z`.\n");

        ASSERT(D1 == Z.data()             );
        ASSERT(D2 == Z.data() + Z.length());

        if (veryVerbose) printf(
                "\tb. Try equality operators: `z` <op> `w`, `x`, `y`, `z`.\n");

        ASSERT(1 == (Z == W));        ASSERT(0 == (Z != W));
        ASSERT(0 == (Z == X));        ASSERT(1 == (Z != X));
        ASSERT(0 == (Z == Y));        ASSERT(1 == (Z != Y));
        ASSERT(1 == (Z == Z));        ASSERT(0 == (Z != Z));

        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        if (verbose) printf("\n 7. Assign `w` from `x`."
                            "\t\t\t\t{ w:A x:A y:A z:D }\n");
        mW = X;

        if (veryVerbose) printf("\ta. Check new value of `w`.\n");

        ASSERT(A1 == W.data()             );
        ASSERT(A2 == W.data() + W.length());

        if (veryVerbose) printf(
                "\tb. Try equality operators: `w` <op> `w`, `x`, `y`, `z`.\n");

        ASSERT(1 == (W == W));        ASSERT(0 == (W != W));
        ASSERT(1 == (W == X));        ASSERT(0 == (W != X));
        ASSERT(1 == (W == Y));        ASSERT(0 == (W != Y));
        ASSERT(0 == (W == Z));        ASSERT(1 == (W != Z));

        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        if (verbose) printf("\n 8. Assign `w` from `z`."
                            "\t\t\t\t{ w:D x:A y:A z:D }\n");
        mW = Z;

        if (veryVerbose) printf("\ta. Check new value of `w`.\n");

        ASSERT(D1 == W.data()             );
        ASSERT(D2 == W.data() + W.length());

        if (veryVerbose) printf(
                "\tb. Try equality operators: `x` <op> `w`, `x`, `y`, `z`.\n");

        ASSERT(1 == (W == W));        ASSERT(0 == (W != W));
        ASSERT(0 == (W == X));        ASSERT(1 == (W != X));
        ASSERT(0 == (W == Y));        ASSERT(1 == (W != Y));
        ASSERT(1 == (W == Z));        ASSERT(0 == (W != Z));

        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        if (verbose) printf("\n 9. Assign `x` from `x` (aliasing)."
                            "\t\t\t{ w:D x:A y:A z:D }\n");
        mX = X;

        if (veryVerbose) printf("\ta. Check (same) value of `x`.\n");

        ASSERT(A1 == X.data()             );
        ASSERT(A2 == X.data() + X.length());

        if (veryVerbose) printf(
                "\tb. Try equality operators: `x` <op> `w`, `x`, `y`, `z`.\n");

        ASSERT(0 == (X == W));        ASSERT(1 == (X != W));
        ASSERT(1 == (X == X));        ASSERT(0 == (X != X));
        ASSERT(1 == (X == Y));        ASSERT(0 == (X != Y));
        ASSERT(0 == (X == Z));        ASSERT(1 == (X != Z));

      } break;

      default: {
        fprintf(stderr, "WARNING: CASE `%d' NOT FOUND.\n", test);
        testStatus = -1;
      }
    }

    if (testStatus > 0) {
        fprintf(stderr, "Error, non-zero test status = %d.\n", testStatus);
    }

    return testStatus;
}

// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
